<template>
  <div class="col-md-9 left-col pull-right">
    <div class="panel article-body content-body">
      <h1 class="text-center">{{ title }}</h1>
      <div class="article-meta text-center">
        <i class="fa fa-clock-o"></i>
        <abbr>{{ date | moment('from') }}</abbr>
      </div>
      <div class="entry-content">
        <div class="content-body entry-content panel-body">
          <div class="markdown-body" v-html="content"></div>

          <!-- 编辑删除图标 -->
          <div class="panel-footer operate" v-if="auth && uid === 1">
            <div class="actions">
              <a @click="deleteArticle" class="admin" href="javascript:;">
                <i class="fa fa-trash-o"></i>
              </a>
              <a @click="editArticle" class="admin" href="javascript:;">
                <i class="fa fa-pencil-square-o"></i>
              </a>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 点赞 -->
    <div class="votes-container panel panel-default padding-md">
      <div class="panel-body vote-box text-center">
        <div class="btn-group">
          <a
            @click="like"
            href="javascript:;"
            class="vote btn btn-primary popover-with-html"
            :class="likeClass"
          >
            <i class="fa fa-thumbs-up"></i>
            {{ likeClass ? '已赞' : '点赞' }}
          </a>
          <div class="or"></div>
          <button @click="showQrcode = true" class="btn btn-success">
            <i class="fa fa-heart"></i> 打赏
          </button>
        </div>
        <div class="voted-users">
          <div class="user-lists">
            <span v-for="(likeUser,index) in likeUsers" :key="index">
              <!-- 点赞用户是当前用户时，加上类 animated 和 swing 以显示一个特别的动画  -->
              <router-link
                :to="`/${likeUser.uname}`"
                :src="likeUser.uavatar"
                tag="img"
                class="img-thumbnail avatar avatar-middle"
                :class="{ 'animated swing' : likeUser.uid === 1 }"
              ></router-link>
            </span>
          </div>
          <div v-if="!likeUsers.length" class="vote-hint">成为第一个点赞的人吧 😄</div>
        </div>
      </div>
    </div>

    <!-- 打赏弹窗 -->
    <Modal :show.sync="showQrcode" class="text-center">
      <div v-if="user" slot="title">
        <img :src="user.avatar" class="img-thumbnail avatar" width="48">
      </div>
      <div>
        <p class="text-md">玩前端知识，VuejsCaff.com 是个不错的开始</p>
        <div class="payment-qrcode inline-block">
          <h5>扫一扫打开 VuejsCaff.com</h5>
          <p>
            <qrcode-vue value="https://vuejscaff.com/" :size="160"></qrcode-vue>
          </p>
        </div>
      </div>
      <div slot="footer">
        <div class="text-center">玩得开心 :)</div>
      </div>
    </Modal>

    <!-- 评论列表 -->
    <div class="replies panel panel-default list-panel replies-index">
      <div class="panel-heading">
        <div class="total">
          回复数量:
          <b>{{ comments.length }}</b>
        </div>
      </div>
      <div class="panel-body">
        <transition-group id="reply-list" name="fade" tag="ul" class="list-group row">
          <li
            v-for="(comment, index) in comments"
            :key="comment.commentId"
            class="list-group-item media"
          >
            <div class="avatar avatar-container pull-left">
              <router-link :to="`/${comment.uname}`">
                <img :src="comment.uavatar" class="media-object img-thumbnail avatar avatar-middle">
              </router-link>
            </div>
            <div class="infos">
              <div class="media-heading">
                <router-link
                  :to="`/${comment.uname}`"
                  class="remove-padding-left author rm-link-color"
                >{{ comment.uname }}</router-link>
                <!-- 编辑删除图标 -->
                <span v-if="auth" class="operate pull-right">
                  <span v-if="comment.uid === 1">
                    <a href="javascript:;" @click="editComment(comment.commentId, index)">
                      <i class="fa fa-edit"></i>
                    </a>
                    <span>⋅</span>
                    <a href="javascript:;" @click="deleteComment(comment.commentId)">
                      <i class="fa fa-trash-o"></i>
                    </a>
                  </span>
                </span>
                <div class="meta">
                  <a
                    :id="`reply${index + 1}`"
                    :href="`#reply${index + 1}`"
                    class="anchor"
                  >#{{ index + 1 }}</a>
                  <span>⋅</span>
                  <abbr class="timeago">{{ comment.date | moment('from', { startOf: 'second' }) }}</abbr>
                </div>
              </div>

              <div class="preview media-body markdown-reply markdown-body" v-html="comment.content"></div>
            </div>
          </li>
        </transition-group>
        <div v-show="!comments.length" class="empty-block">暂无评论~~</div>
      </div>
    </div>

    <!-- 评论框 -->
    <div id="reply-box" class="reply-box form box-block">
      <div class="form-group comment-editor">
        <textarea v-if="auth" id="editor"></textarea>
        <textarea
          v-else
          disabled
          class="form-control"
          placeholder="需要登录后才能发表评论."
          style="height:172px"
        ></textarea>
      </div>
      <div class="form-group reply-post-submit">
        <button
          id="reply-btn"
          :disabled="!auth"
          @click="comment"
          class="btn btn-primary"
        >{{ commentId ? '保存编辑' : '回复' }}</button>
        <span
          v-show="commentId"
          class="help-inline btn-cancel"
          style="cursor:pointer"
          @click="cancelEditComment"
        >取消编辑</span>
        <span v-show="!commentId" class="help-inline">Ctrl+Enter</span>
      </div>
      <div
        v-show="commentHtml"
        id="preview-box"
        class="box preview markdown-body"
        v-html="commentHtml"
      ></div>
    </div>
  </div>
</template>

<script>
import SimpleMDE from "simplemde";
import hljs from "highlight.js";
import emoji from "node-emoji";
import { mapState } from "vuex";
import QrcodeVue from "qrcode.vue";

export default {
  name: "Content",
  components: { QrcodeVue },
  data() {
    return {
      title: "", // 文章标题
      content: "", // 文章内容
      date: "",
      uid: 1,
      likeUsers: [], // 点赞用户列表
      likeClass: "", // 点赞样式
      showQrcode: false, // 是否显示打赏弹窗
      commentHtml: "",
      comments: [],
      commentId: undefined
    };
  },

  // 混入计算属性
  computed: {
    ...mapState(["auth", "user"])
  },

  created() {
    // 从路由中获取文章id
    const articleId = this.$route.params.articleId;
    const article = this.$store.getters.getArticleById(articleId);

    if (article) {
      // 获取当前文章的likeUsers
      let { title, content, date, uid, likeUsers, comments } = article;

      this.uid = uid;
      this.title = title;
      // 使用emoji.emojify解析符号表情
      this.content = SimpleMDE.prototype.markdown(
        emoji.emojify(content, name => name)
      );
      this.date = date;
      this.likeUsers = likeUsers || [];
      // 点赞用户列表包含当前用户时，赋值为 active，表示已赞
      this.likeClass = this.likeUsers.some(likeUser => likeUser.uid === 1)
        ? "active"
        : "";

      // 渲染文章评论
      this.renderComments(comments);

      // $nextTick会在整个视图渲染完毕之后，执行回调
      this.$nextTick(() => {
        // 查找文档中的代码部分全部高亮
        this.$el.querySelectorAll("pre code").forEach(el => {
          hljs.highlightBlock(el);
        });
      });
    }
    // 私有数据，方便执行删除操作
    this.articleId = articleId;
  },

  // el被新创建的vm.$el替换，并挂载到实例上去之后调用该钩子
  mounted() {
    if (this.auth) {
      window.hljs = hljs;

      const simplemde = new SimpleMDE({
        element: document.querySelector("#editor"),
        placeholder:
          "请使用 Markdown 格式书写 ;-)，代码片段黏贴时请注意使用高亮语法。",
        spellChecker: false,
        autoDownloadFontAwesome: false,
        // 不显示工具栏
        toolbar: false,
        // 不显示状态栏
        status: false,
        renderingConfig: {
          codeSyntaxHighlighting: true
        }
      });

      // 插件内容改变监听
      simplemde.codemirror.on("change", () => {
        // 更新 commentMarkdown为编辑器内容
        this.commentMarkdown = simplemde.value();
        // 使用emoj标识，后将内容转为html
        this.commentHtml = simplemde.markdown(
          emoji.emojify(this.commentMarkdown, name => name)
        );
      });

      // 按键松开监听,内容提交(使用箭头函数，在于绑定this指向为当前实例)
      simplemde.codemirror.on("keyup", (codemirror, event) => {
        if (event.ctrlKey && event.keyCode === 13) {
          this.comment();
        }
      });

      // 将编辑器添加到当前实例
      this.simplemde = simplemde;
    }
  },

  methods: {
    editArticle() {
      this.$router.push({
        name: "Edit",
        params: { articleId: this.articleId }
      });
    },
    // 删除
    deleteArticle() {
      this.$swal({
        text: "你确定要删除此内容吗?",
        confirmButtonText: "删除"
      }).then(res => {
        if (res.value) {
          this.$store.dispatch("post", { articleId: this.articleId });
        }
      });
    },

    // 点赞
    like(e) {
      if (!this.auth) {
        this.$swal({
          text: "需要登录以后才能执行此操作。",
          confirmButtonText: "前往登录"
        }).then(res => {
          if (res.value) {
            this.router.push("/auth/login");
          }
        });
      } else {
        const target = e.currentTarget;
        const active = target.classList.contains("active");
        const articleId = this.articleId;

        if (active) {
          // 清除已赞样式
          this.likeClass = "";
          // 分发like事件取消点赞
          this.$store.dispatch("like", { articleId }).then(() => {
              // 使用带用户信息的点赞用户
              this.likeUsers = this.recompute("likeUsers");
          });
        } else {
          // 添加已赞样式及动画
          this.likeClass = "active animated rubberBand";
          this.$store
            .dispatch("like", { articleId, isAdd: true })
            .then(() => {
              // 使用带用户信息的点赞用户
              this.likeUsers = this.recompute("likeUsers");
            });
        }
      }
    },

    // 评论
    comment() {
      if (this.commentMarkdown && this.commentMarkdown.trim() !== "") {
        // 派发comment动作到vuex.store实例
        // 注意dispatch默认返回的是一个promise对象
        this.$store
          .dispatch("comment", {
            comment: { content: this.commentMarkdown },
            articleId: this.articleId,
            commentId: this.commentId
          })
          .then(this.renderComments); //在回调内渲染

        if (this.commentId) {
          // 有 commentId 时，取消编辑评论
          this.cancelEditComment();
        } else {
          // 没有 commentId 时，写入原来的逻辑
          this.simplemde.value("");
          document.querySelector("#reply-btn").focus();

          // 将最后的评论流动到页面的顶部
          this.$nextTick(() => {
            const lastComment = document.querySelector(
              "#replay-list li:last-child"
            );
            if (lastComment) lastComment.scrollIntoView(true);
          });
        }
      }
    },

    // 渲染评论
    renderComments(comments) {
      if (Array.isArray(comments)) {
        // 使用带用户信息的评论
        comments = this.recompute("comments");
        // 深拷贝不影响comments原值
        const newComments = comments.map(comment => ({ ...comment }));

        for (let comment of newComments) {
          //  comment已经有uname 和 uavatar这两个数据了
          // 将评论内容从markdown转成html
          comment.content = SimpleMDE.prototype.markdown(
            emoji.emojify(comment.content, name => name)
          );
        }

        // 更新实例的comments
        this.comments = newComments;
        // 将 Markdown 格式的评论添加到当前实例
        this.commentsMarkdown = comments;
      }
    },

    // 编辑评论
    editComment(commentId, commentIndex) {
      const simplemde = this.simplemde;
      const codemirror = simplemde.codemirror;
      // Markdown格式的所有评论
      const comments = this.commentsMarkdown;

      for (const comment of comments) {
        if (parseInt(comment.commentId) === parseInt(commentId)) {
          simplemde.value(comment.content);
          codemirror.focus();
          // 设置光标显示位置
          codemirror.setCursor(codemirror.lineCount(), 0);
          // 评论索引+1，用来指示页面流动的位置
          this.commentIndex = commentIndex + 1;
          // 更新commentId
          this.commentId = commentId;
          break;
        }
      }
    },

    // 取消编辑评论
    cancelEditComment() {
      // 清除
      this.commentId = undefined;
      this.simplemde.value("");

      // 下次Dom更新后，将评论滚回到视图的顶部
      this.$nextTick(() => {
        if (this.commentIndex === undefined) return;
        const currentComment = document.querySelector(
          `#reply-list li:nth-child(${this.commentIndex})`
        );
        if (currentComment) {
          currentComment.scrollIntoView(true);
          currentComment.querySelector(".operate a").focus();
        }
      });
    },

    // 删除评论
    deleteComment(commentId) {
      // $swal返回一个promise对象
      this.$swal({
        text: "你确定要删除此评论吗?",
        confirmButtonText: "删除"
      }).then(res => {
        if (res.value) {
          this.$store
            .dispatch("comment", {
              commentId,
              articleId: this.articleId
            })
            .then(this.renderComments);
          this.cancelEditComment();
        }
      });
    },

    // 返回带用户信息的文章的某项属性值
    recompute(key) {
      const articleId = this.$route.params.articleId;
      // 基于 getters.computedArticles 包含用户信息了
      const article = this.$store.getters.getArticleById(articleId);
      let arr;

      if (article) {
        arr = article[key];
      }
      return arr || [];
    }
  }
};
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
</style>
